package com.wzw.basics.concurrent.thread;

/**
 * Synchronized 线程同步
 * 底层是依靠，锁对象 monitorObject 。
 * Synchronized 是隐式可重入锁，
 * 当线程需要进行到同步区域时，必须选取获取锁。
 *
 */
public class ThreadSynchronize {
    /**
     * 同步方法，锁是当前实例对象
     */
    public synchronized void method(){

    }

    /**
     * 静态同步方法，锁是当前类
     */
    public synchronized static void staticMethod(){

    }

    /**
     * 同步代码块，锁是指定的对象。一般来说会指定为 this 或者 class
     */
    public void method3(){
        synchronized (this){

        }
    }
    public static void method4(){
        synchronized (ThreadSynchronize.class){

        }
    }

    /**
     * synchronize 同步方法底层原理
     * 使用 javap -c A.class 编译文件，可得到如下，同步方法是使用 ACC_SYNCHRONIZED 标识来进行线程同步。
     *   public synchronized void method5();
     *   descriptor: ()V
     *   flags: ACC_PUBLIC, ACC_SYNCHRONIZED
     *   Code:
     *     stack=0, locals=1, args_size=1
     *        0: return
     *     LineNumberTable:
     *       line 247: 0
     *     LocalVariableTable:
     *       Start  Length  Slot  Name   Signature
     *           0       1     0  this   Lcom/wzw/basics/concurrent/ThreadSynchronize;
     */
    public synchronized void method5(){

    }

    /**
     * synchronize 同步代码块原理
     * 使用 javap -c A.class 编译文件，可得到如下：
     * monitorenter 代表尝试获取锁，如果锁的计数器为0则表示锁可以被获取，获取到锁之后会把锁计数器加1.当同一个线程再次获取同一把锁时，会判断当前线程是否是占用锁的线程，如果是则把锁计数器在次加1.
     * monitorexit 代表释放锁，将锁计数器减1，退出同步代码块。
     * 一般来说 monitorenter 与 monitorexit 是成对出现的，这里 monitorexit 出现了两次是为了保证当程序出现异常时也必须要释放锁。
     *
     *   public void method6();
     *     descriptor: ()V
     *     flags: ACC_PUBLIC
     *     Code:
     *       stack=2, locals=3, args_size=1
     *          0: aload_0
     *          1: dup
     *          2: astore_1
     *          3: monitorenter
     *          4: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
     *          7: ldc           #4                  // String synchronize method
     *          9: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     *         12: aload_1
     *         13: monitorexit
     *         14: goto          22
     *         17: astore_2
     *         18: aload_1
     *         19: monitorexit
     *         20: aload_2
     *         21: athrow
     *         22: return
     *       Exception table:
     *          from    to  target type
     *              4    14    17   any
     *             17    20    17   any
     *       LineNumberTable:
     *         line 253: 0
     *         line 254: 4
     *         line 255: 12
     *         line 256: 22
     *       LocalVariableTable:
     *         Start  Length  Slot  Name   Signature
     *             0      23     0  this   Lcom/wzw/basics/concurrent/ThreadSynchronize;
     *       StackMapTable: number_of_entries = 2
     *         frame_type = 255 /* full_frame
     */
    public void method6(){
        synchronized (this){
            System.out.println("synchronize method");
        }
    }

    public static void main(String[] args) {
        ThreadSynchronize threadSynchronize = new ThreadSynchronize();
        threadSynchronize.method6();
    }
}
